"""
@-*- coding: utf-8 -*-
@ python：python 3.8
@ 创建人员：ylx
@ 创建时间：2025/2/28 下午2:44
@ 内容：cookie  session  token的区别
"""
"""
https://zhuanlan.zhihu.com/p/631349844
HTTP 协议是无状态的，所谓的无状态就是客户端每次想要与服务端通信，都必须重新与服务端链接
意味着请求一次客户端和服务端就连接一次,下一次请求与上一次请求是没有关系的。

无状态的方式就会存在一个问题：如何判断两次请求的是同一个人？就好比用户在页面 A 发起请求获取个人信息，然后在另一个页面同样发起请求获取个人信息
我们如何确定这俩个请求是同一个人发的呢？

为了解决这种问题，我们就迫切需要一种方式知道发起请求的客户端是谁？此时，cookie、token、session 就出现了
它们就可以解决客户端标识的问题，在扩大一点就是解决权限问题。
它们就好比让每个客户端或者说登录用户有了自己的身份证，我们可以通过这个身份证确定发请求的是谁！

cookie 是一种在客户端存储数据的技术
它是由服务器发送给客户端的小型文本文件，存储在客户端的浏览器中,大小限制大致在 4KB 左右
在客户端发送请求时，浏览器会自动将相应的 Cookie 信息发送给服务器
服务器通过读取 Cookie 信息，就可以判断该请求来自哪个客户端
Cookie 可以用于存储用户的登录状态、购物车信息等。
在以前很多开发人员通常用 cookie 来存储各种数据，后来随着更多浏览器存储方案的出现
cookie 存储数据这种方式逐渐被取代，主要原因有如下
1、cookie 有存储大小限制，4KB 左右。

2、浏览器每次请求会携带 cookie 在请求头中。

3、字符编码为 Unicode，不支持直接存储中文。

4、数据可以被轻易查看。

流程（可以想象去饭店吃饭的流程，给了你个牌子）
客户端发送请求到服务端（比如登录请求）。
服务端收到请求后生成一个 session 会话。
服务端响应客户端，并在响应头中设置 Set-Cookie。Set-Cookie 里面包含了 sessionId
它的格式如下：Set-Cookie: value[; expires=date][; domain=domain][; path=path][; secure]
其中 sessionId 就是用来标识客户端的，类似于去饭店里面，服务员给你一个号牌，后续上菜通过这个号牌来判断上菜到哪里。
客户端收到该请求后，如果服务器给了 Set-Cookie，那么下次浏览器就会在请求头中自动携带 cookie。
客户端发送其它请求，自动携带了 cookie，cookie 中携带有用户信息等。
服务端接收到请求，验证 cookie 信息，比如通过 sessionId 来判断是否存在会话，存在则正常响应。

特点
cookie 存储在客户端
cookie 不可跨域，但是在如果设置了 domain，那么它们是可以在一级域名和二级域名之间共享的。


session
session 由服务端创建，当一个请求发送到服务端时
服务器会检索该请求里面有没有包含 sessionId 标识
如果包含了 sessionId，则代表服务端已经和客户端创建过 session
然后就通过这个 sessionId 去查找真正的 session
如果没找到，则为客户端创建一个新的 session
并生成一个新的 sessionId 与 session 对应
然后在响应的时候将 sessionId 给客户端
通常是存储在 cookie 中
如果在请求中找到了真正的 session，验证通过，正常处理该请求。

每一个客户端与服务端连接，服务端都会为该客户端创建一个 session
并将 session 的唯一标识 sessionId 通过设置 Set-Cookie 头的方式响应给客户端
客户端将 sessionId 存到 cookie 中

通常情况下，cookie 和 session 都是结合着来用
当然你也可以单独只使用 cookie 或者单独只使用 session
这里我们就将 cookie 和 session 结合着来用
如下图，具体流程介绍看上面cookie流程即可。

1.客户端 发送登录请求
2.服务器  相应  创建一个session  并将session唯一标识session id 设置在set-cookie的响应头中
响应给客户端
3.客户端发送其他请求并自动携带cookie，服务端通过session id 找到session  没找到则重新创建session
4.服务端  cookie验证通过，正常响应请求

与cookie的区别
cookie 和 session，它们两者之间主要是通过 sessionId 关联起来的
所以总结出：sessionId 是 cookie 和 session 之间的桥梁。
session 是基于 cookie 实现的，它们两个主要有以下特点：
session 比 cookie 更加安全，因为它是存在服务端的，cookie 是存在客户端的。
cookie 只支持存储字符串数据，session 可以存储任意数据。
cookie 的有效期可以设置较长时间，session 有效期都比较短。
session 存储空间很大，cookie 有限制。
系统想要实现鉴权，可以单独使用 cookie，也可以单独使用 session，但是建议结合两者使用。


token是什么
是一种在客户端和服务端之间传递身份信息的方式。
当用户登录成功后，服务端会生成一个 Token，将其发送给客户端
客户端在后续的请求中，需要将 Token 携带在请求头或请求参数中
服务端通过验证 Token 的合法性，就可以确定该请求来自哪个用户，并且可以根据用户的权限进行相应的操作
Token 可以有效地避免了 Cookie 的一些安全问题

Token是一个由一串字符组成的令牌，用于在计算机系统中进行身份验证和授权
它通常由三个部分组成：标头、有效载荷、签名。

认证流程
客户端发起登录请求，比如用户输入用户名和密码后登录。
服务端校验用户名和密码后，将用户 id 和一些其它信息进行加密，生成 token。
服务端将 token 响应给客户端。
客户端收到响应后将 token 存储下来。
下一次发送请求后需要将 token 携带上，比如放在请求头中或者其它地方。
服务端 token 后校验，校验通过则正常返回数据。

cookie
特点 1.存储在客户端。2.请求自动携带 cookie。3.存储大小 4KB。
优点 1.兼容性好，因为是比较老的技术。2.很容易实现，因为 cookie 会自动携带和存储。
缺点 1.需要单独解决跨域携带问题，比如多台服务器如何共享 cookie。2.会遭受 CSRF 攻击。3.存储在客户端，不够安全

session
特点 1.存储在服务端。2.存储大小无限制。
优点 1.查询速度快，因为是个会话，相当于是在内存中操作。2.结合 cookie 后很容易实现鉴权。3.安全，因为存储在服务端。
缺点 1.耗费服务器资源，因为每个客户端都会创建 session。2.占据存储空间，session 相当于存储了一个完整的用户信息

token
特点 1.体积很小。2.自由操作存储在哪里
优点 1.安全，因为 token 一般只有用户 id，就算被截取了也没什么用。2.无需消耗服务器内存资源，它相当于只存了用户 id，session 相当于存储了用户的所有信息
3.跨域处理较为方便，比如多台服务器之间可以共用一个 token。
缺点 1.查询速度慢，因为 token 只存了用户 id，每次需要去查询数据库。


session 是空间换时间，token 是时间换空间。

为什么说session比cookie安全，session不也是通过set cookie返回给客户端吗？
客户端会存这个sessionid  那不是也容易泄漏信息，因为是通过sessionid 来和服务器交互获取用户的信息？
答：Session 的安全性并不在于它是否通过 Cookie 传递 Session ID，而在于它的设计和实现方式。
下面我们详细分析为什么说 Session 比直接使用 Cookie 更安全。
Session 的工作原理
当用户登录时，服务器生成一个唯一的 Session ID，并将其存储在服务器端的内存或数据库中。
同时，服务器将这个 Session ID 返回给客户端（通常是通过 Set-Cookie 响应头）。
客户端在后续请求中携带该 Session ID（通过 Cookie 请求头），服务器通过解析 Session ID 来恢复用户的会话状态。
关键区别
虽然 Session ID 是通过 Cookie 传递的，但实际的会话数据（如用户名、权限等）是存储在服务器端的，而不是存储在客户端
这就是 Session 和直接使用 Cookie 的核心区别。

为什么说 使用Session 比直接使用 Cookie 更安全？
(1) 数据存储位置
Cookie：直接将敏感数据（如用户名、密码或其他用户信息）存储在客户端。如果 Cookie 被窃取，攻击者可以直接获取这些敏感数据。
Session：只将 Session ID 存储在客户端，实际的会话数据存储在服务器端。即使攻击者窃取了 Session ID，也无法直接访问服务器上的会话数据。
数据加密
Cookie：通常以明文形式存储在客户端（除非手动加密）。如果未设置 HttpOnly 和 Secure 标志，Cookie 很容易被恶意脚本读取。
Session：服务器端的会话数据可以进行加密存储，并且可以通过其他机制（如 IP 绑定、指纹验证等）进一步增强安全性。

生命周期管理
Cookie：生命周期由开发者设定，但如果未正确配置（如未设置 Expires 或 Max-Age），可能会导致 Cookie 长时间保留在客户端。
Session：服务器可以更灵活地管理会话的生命周期（如超时、强制销毁等），从而降低被滥用的风险。

数据完整性
Cookie：客户端可以修改 Cookie 的内容，可能导致数据完整性问题。
Session：服务器端完全控制会话数据，客户端无法篡改

Session 的安全性主要体现在它将敏感数据存储在服务器端，而不是客户端。
尽管 Session ID 是通过 Cookie 传递的，但其本身只是一个标识符
攻击者即使窃取了 Session ID，也无法直接访问服务器上的会话数据。


为什么即使攻击者窃取了 Session ID，也无法直接访问服务器上的会话数据。
我们需要从 Session 的设计原理 和 服务器端的安全机制 两个方面来分析。
设计原理
Session ID 只是标识符
Session ID 是一个随机生成的唯一标识符，用于区分不同的用户会话。
它本身并不包含任何敏感数据，只是一个“钥匙”，用来指向服务器端存储的实际会话数据。
攻击者即使窃取了 Session ID，也只知道“钥匙”是什么，但无法直接看到或修改这把“钥匙”对应的“房间”（即服务器上的会话数据）
实际数据存储在服务器端
在 Session 的实现中，用户的敏感数据（如用户名、权限等）存储在服务器端的内存或数据库中。
每个 Session ID 对应一个唯一的会话数据结构，只有服务器才能访问和解析这些数据。
攻击者即使知道了 Session ID，也无法直接获取或修改服务器上的会话数据。

那攻击者窃取了session id 后 是否可以访问这个用户的数据，伪造用户的操作，从而造成信息泄露
是的，攻击者如果成功窃取了 Session ID，确实可以利用它冒充合法用户
访问该用户的数据或伪造用户的操作。这种行为可能导致敏感信息泄露或其他安全问题
然而，这种情况的发生通常依赖于某些特定条件和漏洞的存在。下面我们详细分析这个问题。

如何防止
设置 HttpOnly 和 Secure 标志
使用 HTTPS 协议
IP 绑定
设备指纹验证
动态 Token 验证
超时机制
对于关键操作（如密码修改、资金转移等），要求用户进行额外的身份验证（如短信验证码、邮箱确认等）。
定期更换 Session ID，在用户登录、注销或会话恢复时，定期更换 Session ID，以减少被滥用的风险。
"""